/*
 * @Author       : Atonidas
 * @LastEditors  : Atonidas
 * @LastEditTime : 2023-11-03 15:24:27
 * @FilePath     : \3.Received\User\User\user.c
 * @Description  : 项目中的用户函数，主要为不通用的交互菜单等代码
 */

#include "Encoder\Encoder.h"
#include "OLED\oled.h"
#include "User\user.h"
#include "tim.h"
#include "Flash\MCU_Flash.h"

#define NUM_CHANNELS  8
#define HOLD_TIME_MAX 320 // 长按时间最大值
#define HOLD_TIME_MIN 280  // 长按时间最小值

unsigned int Flash_Data[17] = {0};

// 记录器数据结构体
typedef struct {
    uint16_t pin;              // 具体的引脚号
    unsigned int timerValue;   // 存放引脚的计数器值
    unsigned int successCount; // 成功次数
    unsigned int failureCount; // 失败次数
} GPIO_CHANNEL;

GPIO_CHANNEL channels[NUM_CHANNELS] = {
    {CH0_Pin, 0, 0, 0},
    {CH1_Pin, 0, 0, 0},
    {CH2_Pin, 0, 0, 0},
    {CH3_Pin, 0, 0, 0},
    {CH4_Pin, 0, 0, 0},
    {CH5_Pin, 0, 0, 0},
    {CH6_Pin, 0, 0, 0},
    {CH7_Pin, 0, 0, 0},
};

// 记录状态枚举
enum eRecordState {
    Record_Wait = 0,
    Record_Work,
};

void Main_Dispaly(void);
void Update_Display(void);

/**
 * @description: 用户主服务函数，用于UI初始化及主要参数显示界面（//TODO:）
 * @param parameter 线程入口参数，默认无
 * @return
 */
void userApp_thread_entry(void *parameter)
{
    unsigned Reset_Count     = 0;
    unsigned short Min_Limit = 10 * HOLD_TIME_MIN, Max_Limit = 10 * HOLD_TIME_MAX;
    User_Data_Read();
    rt_kprintf("\r\n\r\nReceive Min:%d Max:%d\r\n\r\n", Min_Limit, Max_Limit);
    rt_kprintf(" CH | Success | failure\r\n");
    for (uint8_t i = 0; i < 8; i++) {
        rt_kprintf(" %02d |   %05d |   %05d\r\n", i + 1, channels[i].successCount, channels[i].failureCount);
    }
    OLED_Init();
    OLED_Clear_Screen(0x00);

    Main_Dispaly();
    for (;;) {
        if (HAL_GPIO_ReadPin(EC11_C_GPIO_Port, EC11_C_Pin) == 0) {
            Reset_Count++;
        } else {
            Reset_Count = 0;
        }

        if (Reset_Count > 20) {
            for (uint8_t i = 0; i < 8; i++) {
                channels[i].successCount = 0;
                channels[i].failureCount = 0;
            }
            User_Data_Save();
            OLED_Clear_Screen(0);
            OLED_ShowString(0, 24, "Data Clear!!", 15, 0);
            rt_thread_mdelay(1000);
            OLED_Clear_Screen(0);
            Main_Dispaly();
        }
        Update_Display();
    }
}

static uint8_t Record_State = Record_Wait;
static uint16_t Idle_Timer = 0, Record_Timer = 0;
void UpdateRecordState(void)
{
    if (Record_State == Record_Work) {
        Idle_Timer++;
    }
    if (Idle_Timer >= 100) // 10s
    {
        Idle_Timer   = 0;
        Record_Timer = 0;
        Record_State = Record_Wait;
    }
}

void UpdateTimer(void)
{
    if (Record_State == Record_Work) {
        Record_Timer++;
    }
}

void UpdateRecorder(uint16_t GPIO_Pin, uint8_t mode)
{
    Idle_Timer            = 0;
    GPIO_CHANNEL *channel = NULL;
    for (int i = 0; i < NUM_CHANNELS; i++) {   // 遍历通道数组
        if (channels[i].pin == GPIO_Pin) {     // 查找匹配的通道
            if (Record_State == Record_Wait) { // 如果记录状态为等待状态，表示第一次触发记录
                Record_State = Record_Work;    // 修改记录状态为工作状态
                Record_Timer = 0;
            }
            channel = &channels[i]; // 将匹配的通道赋值给指针变量
            break;                  // 跳出循环
        }
    }
    if (channel != NULL) {                                     // 如果通道不为空
        if (mode == CHANNEL_START) {                           // 如果模式为 0，表示读取定时器值
            channel->timerValue = Record_Timer;                // 将定时器的值保存到通道结构体中
        } else if (mode == CHANNEL_END) {                      // 如果模式为 1，表示检测按键释放状态
            int timeDiff = Record_Timer - channel->timerValue; // 计算时间差
                                                               // 检查时间差是否在指定范围内
                                                               rt_kprintf("t:%d\r\n", timeDiff);
            if (timeDiff >= HOLD_TIME_MIN && timeDiff <= HOLD_TIME_MAX) {
                channel->successCount++; // 更新成功次数
            } else {
                channel->failureCount++; // 更新失败次数
            }
        }
    } // 读取定时器值
}

void Encoder_MainMenu(void)
{
    OLED_FillArea(0, 16, SCREEN_W, 32, 0);
    OLED_ShowString(0, 16, encoder_services[getEncoderValue(0)].name, 15, 0);
}

void Main_Dispaly(void)
{
    OLED_ShowString(0, 0, "C1:       C2:     ", 15, 0);
    OLED_ShowString(0, 16, "C3:       C4:     ", 15, 0);
    OLED_ShowString(0, 32, "C5:       C6:     ", 15, 0);
    OLED_ShowString(0, 48, "C7:       C8:     ", 15, 0);
}

void Update_Display(void)
{
    OLED_ShowNumber(32, 0, channels[0].successCount, 5, 15, 0);
    OLED_ShowNumber(112, 0, channels[1].successCount, 5, 15, 0);
    OLED_ShowNumber(32, 16, channels[2].successCount, 5, 15, 0);
    OLED_ShowNumber(112, 16, channels[3].successCount, 5, 15, 0);
    OLED_ShowNumber(32, 32, channels[4].successCount, 5, 15, 0);
    OLED_ShowNumber(112, 32, channels[5].successCount, 5, 15, 0);
    OLED_ShowNumber(32, 48, channels[6].successCount, 5, 15, 0);
    OLED_ShowNumber(112, 48, channels[7].successCount, 5, 15, 0);
}

void User_Data_Read(void)
{
    STMFLASH_Read(FLASH_USER_START_ADDR, Flash_Data, 17);
    if (Flash_Data[16] == 0) {
        for (uint8_t i = 0; i < 8; i++) {
            channels[i].successCount = Flash_Data[i];
            channels[i].failureCount = Flash_Data[i + 8];
        }
    }
}

void User_Data_Save(void)
{
    for (uint8_t i = 0; i < 8; i++) {
        Flash_Data[i]     = channels[i].successCount;
        Flash_Data[i + 8] = channels[i].failureCount;
    }
    Flash_Data[16] = 0;
    MCU_Flash_EraseProgram(FLASH_USER_START_ADDR, FLASH_USER_END_ADDR, 17, Flash_Data);
}